import requests
import re
import json
import js2py
from typing import List, Dict
from beautifultable import BeautifulTable


def extract_bcur_ranking_data(url: str) -> List[Dict]:
    try:
        # 发送请求获取数据
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        }
        response = requests.get(url, headers=headers)
        response.encoding = 'utf-8'

        if response.status_code != 200:
            print(f"请求失败，状态码: {response.status_code}")
            return []

        content = response.text

        # 提取整个JSONP函数调用
        pattern = r'__NUXT_JSONP__\("/rankings/bcur/\d+",\s*\(function\(([^)]*)\)\s*{([\s\S]*)}\s*\(([^)]*)\)\)\);'
        match = re.search(pattern, content)

        if not match:
            print("未找到JSON数据")
            return []

        # 获取函数参数、函数体和实际参数
        func_params = match.group(1)  # 函数参数: a, b, c, d, e, f, ...
        function_body = match.group(2)  # 函数体
        actual_params = match.group(3)  # 实际参数值

        # 使用js2py执行JavaScript代码
        return extract_with_js_engine(func_params, function_body, actual_params)

    except Exception as e:
        print(f"提取数据时出错: {e}")
        return []


def extract_with_js_engine(func_params: str, function_body: str, actual_params: str) -> List[Dict]:
    """
    使用JavaScript引擎执行函数并提取数据
    """
    try:
        # 创建JavaScript执行环境
        context = js2py.EvalJs()

        # 构建完整的JavaScript代码
        js_code = f"""
        // 定义函数
        function getData({func_params}) {{
            {function_body}
        }}

        // 调用函数并返回结果
        var result = getData({actual_params});

        // 返回univData数组
        result.data[0].univData;
        """

        # 执行JavaScript代码
        univ_data = context.eval(js_code)
        # 转换为Python列表
        universities = []
        for univ in univ_data:
            university_info = {
                '排名': univ.get('ranking', ''),
                '学校名称': univ.get('univNameCn', ''),
                '英文名称': univ.get('univNameEn', ''),
                '学校类型': univ.get('univCategory', ''),
                '所在省份': univ.get('province', ''),
                '总分': univ.get('score', '')
            }
            universities.append(university_info)

        return universities

    except Exception as e:
        print(f"JavaScript执行失败: {e}")
        return []


def save_to_excel(data: List[Dict], filename: str = '大学排名数据.xlsx'):
    """将数据保存为Excel文件"""
    import pandas as pd
    if not data:
        print("没有数据可保存")
        return

    df = pd.DataFrame(data)
    df.to_excel(filename, index=False, engine='openpyxl')
    print(f"数据已保存到 {filename}")


def main():
    # 目标URL
    url = "https://www.shanghairanking.cn/_nuxt/static/1761118404/rankings/bcur/202111/payload.js"

    print("开始提取大学排名数据...")

    # 提取数据
    universities = extract_bcur_ranking_data(url)

    if universities:
        print(f"成功提取 {len(universities)} 所大学的数据")

        # 显示前几行数据
        table = BeautifulTable()
        table.set_style(BeautifulTable.STYLE_COMPACT)
        table.columns.header = ["排名", "学校名称", "英文名称", "学校类型", "所在省份", "总分"]
        table.columns.alignment = BeautifulTable.ALIGN_CENTER
        table.columns.width = [6, 12, 20, 12, 12, 12]
        print("\n前100所大学排名:")
        for i, univ in enumerate(universities[:100]):
            table.rows.append(
                [univ["排名"], univ["学校名称"], univ["英文名称"], univ["学校类型"], univ["所在省份"], univ["总分"]])
        print(table)
        print()

        # 保存数据
        save_to_excel(universities, '软科中国大学排名2021.xlsx')

    else:
        print("未能提取到数据")


if __name__ == "__main__":
    main()